#!/bin/bash

addTestUser()
{
    #add testUserForTone
    grep testUserForTone /etc/passwd
    if [[ 0 -ne $? ]] ; then
        sudo bash ${TONE_SUITE_DIR}/mysql-server/adduser.sh testUserForTone
        if [[ -n "${ROOT_ID}" ]] ; then
            echo "${ROOT_ID}" > /tmp/root_id
            echo "${ROOT_ID}" >> /tmp/root_id
            sudo passwd root < /tmp/root_id
            rm -rf /tmp/root_id
        fi
    fi
}

check_dep()
(
    which $1
    if [[ 0 -ne $? ]] ; then
        echo "can't find $1!"
        return 1
    fi
)

#echo the command
function log_echo()
{
  date=$(date +'%F %T')
  echo -e "\n$date"
  echo -e "$@"
}

#echo and execute the command
function log_cmd()
{
  log_echo "$@"
  eval "$@" 2>&1
}

install_package()
{
    if [[ $(grep ID_LIKE /etc/os-release | grep debian) ]] ; then
        sudo apt-get install -y $* || die "apt-get install -y $* fail!"
    elif [[ $(grep ID_LIKE /etc/os-release | grep -E "(centos)|(fedora)") ]] || [[ $(grep -E "(ID_LIKE)|(PRETTY_NAME)" /etc/os-release | grep -i anolis) ]] ; then
        sudo yum install -y $* || die "yum install -y $* fail!"
    fi
}

git_clone()
{
    unset GIT_SSH
    unset GIT_SSH_COMMAND
    maxCount=20
    if [[ $# -ne 2 ]] ; then
        die "LINENO=${LINENO} git_clone expect 2 args!"
    fi
    dir=$2
    for i in `seq ${maxCount}`
    do
        logger rm -rf ${dir}
        if [[ -d "$dir" ]] ; then
            die "LINENO=${LINENO} rm -rf ${dir} fail!"
        fi
        logger "$1 ${dir}"
        if [[ 0 -eq $? ]] ; then
            break
        elif [[ $i -eq ${maxCount} ]] ; then
            git --version
            which git
            ls -lh ~/.ssh/id_rsa
            file ~/.ssh/id_rsa
            md5sum ~/.ssh/id_rsa
            cat ~/.ssh/known_hosts
            echo GIT_SSH=${GIT_SSH}
            echo GIT_SSH_COMMAND=${GIT_SSH_COMMAND}
            die "LINENO=${LINENO} git clone fail for ${maxCount} times!"
        fi
        sleep 10
    done
}

wget_wrapper()
{
    if [[ $# -lt 1 ]] ; then
        die "LINENO=${LINENO} wget_wrapper expect at least 1 args!"
    fi
    local file=`echo ${1##*/} | xargs python3 -c "import sys; from urllib.parse import unquote; print (unquote(sys.argv[1]))"`
    local max_try_count=10
    local cmd="wget -nv $1"
    for i in `seq ${max_try_count}`
    do
        rm -rf ${file}
        if [[ -f "$file" ]] ; then
            die "LINENO=${LINENO} rm -rf ${file} fail!"
        fi
        logger "${cmd}"
        if [[ 0 -eq $? ]] ; then
            break
        elif [[ $i -eq ${max_try_count} ]] ; then
            die "LINENO=${LINENO} wget fail for 10 times!"
        fi
        sleep 10
    done
    if [[ -n "$2" ]] && [[ "$2" != "${file}" ]] ; then
        mv -f "${file}" "$2"
    fi
}

github_git_clone()
{
    git_clone "GIT_SSH_COMMAND=\"ssh -i ~/.ssh/id_rsa\" $1" $2
}

get_llvm_binary()
{
    logger "get_ssh_key"
    if [[ "${READ_URL_FROM_OSS}" == "1" ]] ; then
        get_binary_url_from_oss
        url=${ossLink}
    elif [[ -n "${BINARY_URL}" ]] ; then
        url="${BINARY_URL}"
    else
        die "LINENO=${LINENO} BINARY_URL=${BINARY_URL} READ_URL_FROM_OSS=${READ_URL_FROM_OSS}!"
    fi
    cd ${TONE_BM_RUN_DIR}/
    export TEST_LLVM=`find . -name clang | grep "bin/clang$" | head -n 1 | xargs realpath 2>/dev/null | xargs dirname 2>/dev/null | xargs dirname 2>/dev/null`  #if there already llvm binary, then use it instead of download
    if [[ -z "${TEST_LLVM}" ]] ; then
        rm -rf binary-download
        mkdir -p binary-download
        pushd binary-download
        #downloadFromOSS "${url}" "${CLOUD_ACCOUNT}" "${OSS_ENDPOINT}" || die "LINENO=${LINENO} download binary ${url} fail!"
        wget_wrapper "${url}" acc-binary.tar.gz || die "LINENO=${LINENO} download binary ${url} fail!"
        md5sum acc-binary.tar.gz
        tar xvf acc-binary.tar.gz &> tar-xvf.log
        grep -q "bin/clang$" tar-xvf.log
        if [[ 0 -eq $? ]] ; then
            export TEST_LLVM=`find . -name clang | grep "bin/clang$" | head -n 1 | xargs realpath | xargs dirname | xargs dirname`
        else
            rpmfile=`find . -name "*.rpm" | grep -v "\.src\." | grep -vw doc | head -n 1`
            md5sum ${rpmfile}
            sudo yum install -y ${rpmfile} 2>&1 | tee acc-yum-install.log || die "acc yum install fail!"
            timeout 1200 rpm2cpio ${rpmfile} | cpio -idmv &> cpio.log
            grep -q "bin/clang$" cpio.log
            if [[ 0 -eq $? ]] ; then
                export TEST_LLVM=`find . -name clang | grep "bin/clang$" | head -n 1 | xargs realpath | xargs dirname | xargs dirname`
            else
                die "LINENO=${LINENO} rpm file error!"
            fi
        fi
    fi
    if [[ -z "${TEST_LLVM}" ]] ; then
        die "LINENO=${LINENO} TEST_LLVM=${TEST_LLVM} is empty!"
    fi
    if [[ -f summary_message.txt ]] ; then
        cat summary_message.txt
    fi
    readelf -S ${TEST_LLVM}/bin/clang
    ${TEST_LLVM}/bin/clang -v
    ret1=$?
    cat <<EOF > hello.c
#include <stdio.h>
int main()
{
  printf("Hello!\n");
  return 0;
}
EOF
    ${TEST_LLVM}/bin/clang hello.c
    ret2=$?
    if [[ ${ret1} -ne $? ]] || [[ ${ret2} -ne 0 ]] ; then
        pushd ${TONE_BM_RUN_DIR}/${LLVM_PROJECT_DIR}
        rm -rf build
        mkdir build
        cd build
        export CC=/usr/bin/gcc
        export CXX=/usr/bin/g++
        if [[ -n "${gcc_home}" ]] ; then
            if [[ -e ${gcc_home}/bin/gcc ]] && [[ -e ${gcc_home}/bin/g++ ]] ; then
                export PATH=${gcc_home}/bin:$PATH
                export CC=${gcc_home}/bin/gcc
                export CXX=${gcc_home}/bin/g++
                export LD_LIBRARY_PATH=${gcc_home}/lib64:${LD_LIBRARY_PATH}
            else
                return 1
            fi
        fi
        cat /etc/os-release  | grep anolis -w
        if [[ 0 -eq $? ]] ; then
            pushd ..
            if [ "$code_source" == "alibaba" ] ; then
                mkdir -p patch
                logger cp -rf ${TONE_SUITE_DIR}/llvm-test-suite/0001-PATCH-AddGCCPrefix-on-anolis.patch patch/0000-PATCH-AddGCCPrefix-on-anolis.patch || return 1
            fi
            git apply patch/0000-PATCH-AddGCCPrefix-on-anolis.patch || return 1
            popd
        fi
        logger cmake -G "Ninja" -DLLVM_ENABLE_PROJECTS="clang\;llvm\;clang-tools-extra\;compiler-rt\;lld\;libcxx\;libcxxabi" -DCMAKE_INSTALL_PREFIX=$PWD/install -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_DUMP=ON -DLLVM_TARGETS_TO_BUILD="X86\;AArch64\;RISCV" -DLLVM_ENABLE_ASSERTIONS=On -DPYTHON_EXECUTABLE=/usr/bin/python3 -DLLVM_CACHE_BUILD=ON ../llvm || return 1
        logger ninja || return 1
        logger ninja install || return 1
        export TEST_LLVM=$PWD/install
    fi
    # export PATH=${TEST_LLVM}/bin:${PATH}
    # echo "export PATH=${TEST_LLVM}/bin:${PATH}" >> ${TONE_BM_RUN_DIR}/.shrc
    echo "export TEST_LLVM=${TEST_LLVM}" >> ${TONE_BM_RUN_DIR}/.shrc
    prepend PATH ${TEST_LLVM}/bin
    ulimit -a
}

write_java_home()
{
    if [[ -z "${JAVA_HOME}" ]] ; then
        die "LINENO=${LINENO} JAVA_HOME=${JAVA_HOME} is empty!"
    fi
    ${JAVA_HOME}/bin/java -version
    ${JAVA_HOME}/bin/java -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -XshowSettings
    export PATH=${JAVA_HOME}/bin:${PATH}
    echo "export PATH=${JAVA_HOME}/bin:${PATH}" >> ${TONE_BM_RUN_DIR}/.shrc
    echo "export JAVA_HOME=${JAVA_HOME}" >> ${TONE_BM_RUN_DIR}/.shrc
}

get_jdk_binary_with_url()
{
    url=$1
    cd ${TONE_BM_RUN_DIR}/
    export JAVA_HOME=`find . -name java | grep "bin/java$" | grep -v "/jre/" |head -n 1 | xargs realpath | xargs dirname | xargs dirname`  #if there already jdk binary, then use it instead of download
    if [[ -z "${JAVA_HOME}" ]] ; then
        rm -rf binary-download
        mkdir -p binary-download
        pushd binary-download
        wget_wrapper "${url}" binary.tar.gz
        tar xvf binary.tar.gz &> tar-xvf.log
        grep -q "bin/java$" tar-xvf.log
        if [[ 0 -eq $? ]] ; then
            export JAVA_HOME=`find . -name java | grep "bin/java$" | grep -v "/jre/" |head -n 1 | xargs realpath | xargs dirname | xargs dirname`
        else
            if [[ "${MULTI_RPM}" = "true" ]] ; then
                touch cpio.log
                for rpmfile in $(ls *.rpm)
                do
                    timeout 1200 rpm2cpio ${rpmfile} | cpio -idmv &>> cpio.log
                done
                # fix soft link.
                confPath=''
                confLink=''
                for cf in $(find -name conf)
                do
                  if [ -L ${cf} ];then
                    confLink=${cf}
                  elif [ -d ${cf} ];then
                    confPath=${cf}
                  fi
                done
                if [ -n ${confPath} ] && [ -n ${confLink} ];then
                  rm -rf ${confLink}
                  ln -sf $(pwd)/${confPath} ${confLink}
                fi
                secPath=''
                secLink=''
                for sec in $(find -iname security | grep -vE 'share|conf')
                do
                  if [ -L ${sec} ];then
                    secLink=${sec}
                  elif [ -d ${sec} ];then
                    secPath=${sec}
                  fi
                done
                if [ -n ${secPath} ] && [ -n ${secLink} ];then
                  rm -rf ${secLink}
                  ln -sf $(pwd)/${secPath} ${secLink}
                fi
            else
                rpmfile=`find . -name "*.rpm" | grep -v "\.src\." | head -n 1`
                timeout 1200 rpm2cpio ${rpmfile} | cpio -idmv &> cpio.log
            fi
            grep -q "bin/java$" cpio.log
            if [[ 0 -eq $? ]] ; then
                export JAVA_HOME=`find . -name java | grep "bin/java$" | grep -v "/jre/" |head -n 1 | xargs realpath | xargs dirname | xargs dirname`
            else
                die "LINENO=${LINENO} rpm file error!"
            fi
        fi
    fi
    write_java_home
}

get_jdk_binary()
{
    if [[ "${TEST_SYSTEM_JDK}" == "TRUE" ]] ; then
        if [[ -z "${JAVA_HOME}" ]] ; then
            which java | grep "/bin/java"
            if [[ 0 -ne $? ]] ; then
                die "LINENO=${LINENO} ERROR: TEST_SYSTEM_JDK=${TEST_SYSTEM_JDK} JAVA_HOME=${JAVA_HOME} but can not find java!"
            else
                export JAVA_HOME=`which java | xargs dirname | xargs dirname`
            fi
        else
            ${JAVA_HOME}/bin/java -version
            if [[ 0 -ne $? ]] ; then
                die "LINENO=${LINENO} ${JAVA_HOME}/bin/java -version check fail!"
            fi
        fi
        write_java_home
    elif [[ -n "${DOCKER_IMAGE}" ]] ; then
        addTestUser
        install_package docker
        touch /etc/containers/nodocker
        docker pull ${DOCKER_IMAGE} || die "docker pull ${DOCKER_IMAGE} fail!"
        docker rm -f jtreg
        if [[ -n "${BINARY_URL}" ]] ; then
            get_jdk_binary_with_url "$BINARY_URL"
            echo JAVA_HOME=${JAVA_HOME}
            docker run --rm --privileged docker.io/multiarch/qemu-user-static:latest --reset -p yes || die "docker run multiarch fail!"
            docker run -it --rm --name jtreg-tmp ${DOCKER_IMAGE} bash -c 'echo $PATH' > docker-path.txt || die "docker run ${DOCKER_IMAGE} fail!"
            num=`wc -l docker-path.txt | awk '{print $1}'`
            if [[ 1 -ne $num ]] ; then
                die "LINENO=${LINENO} get docker path fail"
            fi
            docker_path=`cat docker-path.txt`
            docker run --pids-limit -1 -e JAVA_HOME=/opt/java -e PATH=/opt/java/bin:${docker_path} --network host --privileged -h docker -w ${TONE_RUN_DIR} -v /etc/hosts:/etc/hosts:ro -v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro -v /etc/shadow:/etc/shadow:ro --rm -itd -v ${TONE_ROOT}:${TONE_ROOT} --name jtreg ${DOCKER_IMAGE} bash || die "docker run LINENO=${LINENO} ${DOCKER_IMAGE} fail!"
            docker cp ${JAVA_HOME} jtreg:/opt/java || die "docker cp LINENO=${LINENO} ${DOCKER_IMAGE} fail!"
        else
            docker run --pids-limit -1 --network host --privileged -h docker -w ${TONE_RUN_DIR} -v /etc/hosts:/etc/hosts:ro -v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro -v /etc/shadow:/etc/shadow:ro --rm -itd -v ${TONE_ROOT}:${TONE_ROOT} --name jtreg ${DOCKER_IMAGE} bash || die "docker run ${DOCKER_IMAGE} fail!"
        fi
        for i in `seq 10`
        do
            docker exec -it jtreg yum install -y ${DEP_PKG_LIST}
            if [[ 0 -eq $? ]] ; then
                break
            fi
        done
        for i in `seq 10`
        do
            docker exec -it jtreg yum install -y sudo which diffutils file make gcc gcc-c++ time
            yum_ret=$?
            #docker exec -it jtreg apt install -y diffutils file make gcc g++ time
            docker exec -it jtreg apt install -y sudo which diffutils file
            apt_ret=$?
            if [[ 0 -eq ${yum_ret} ]] || [[ 0 -eq ${apt_ret} ]] ; then
                break
            fi
        done
        docker exec -it jtreg ulimit -u unlimited
        echo 'export DOCKER_EXEC="docker exec -w $PWD -it jtreg "' >> ${TONE_BM_RUN_DIR}/.shrc-disposable
        echo 'export DOCKER_EXEC="docker exec -it jtreg "' >> ${TONE_BM_RUN_DIR}/.shrc
        export DOCKER_EXEC="docker exec -it jtreg "
        cd ${TONE_BM_RUN_DIR}/
        mkdir -p excludes/
        cp -rf ${TONE_BM_SUITE_DIR}/excludes/docker.txt excludes/
    else
        if [[ "${READ_URL_FROM_OSS}" == "1" ]] || [[ "${READ_URL_FROM_OSS}" == "TRUE" ]] ; then
            get_jdk_binary_url_from_oss
            url=${ossLink}
        elif [[ -n "${BINARY_URL}" ]] ; then
            url="${BINARY_URL}"
        else
            die "LINENO=${LINENO} BINARY_URL=${BINARY_URL} READ_URL_FROM_OSS=${READ_URL_FROM_OSS} TEST_SYSTEM_JDK=${TEST_SYSTEM_JDK} JAVA_HOME=${JAVA_HOME}"
        fi
        get_jdk_binary_with_url "$url"
    fi
    ulimit -a
}

pack_core_dump_file()
{
    if [[ $# -lt 3 ]] ; then
        die "please input correct args:$@"
    fi
    file=$1
    dir=$2
    if [[ ! -f ${file} ]] ; then
        die "file=${file} is not a regular file!"
    fi
    if [[ ! -d ${dir} ]] ; then
        die "dir=${dir} is not a regular directory!"
    fi
    basename=`basename ${file}`
    dirname=`dirname ${file}`
    mkdir -p ${dir}/${dirname}
    cp -rf ${file} ${dir}/${file}
    pushd ${dir}/${dirname}/ > /dev/null
    # tar jcf ${basename}.tar.bz2 ${basename}
    tar -c ${basename} | xz -9 > ${basename}.tar.xz
    if [[ 0 -eq $? ]] ; then
        rm -rf ${basename}
    else
        return
    fi
    which zip > /dev/null
    if [[ 0 -eq $? ]] ; then
        size=${3:-10M}
        zip -r -9 -s ${size} ${basename}.tar.xz.zip ${basename}.tar.xz
        if [[ 0 -eq $? ]] ; then
            rm -rf ${basename}.tar.xz
        fi
    fi
    popd > /dev/null
}

getJdkVersion()
{
    java -version 2>&1 | head -n 1 | grep " version " > /tmp/java.version
    if [[ 0 -ne $? ]] ; then
        return 1
    fi
    grep -qE "[0-9]+_[0-9]+" /tmp/java.version
    if [[ 0 -eq $? ]] ; then
        cat /tmp/java.version | awk -F \" '{print $2}' | awk -F . '{print $2}'
    else
        cat /tmp/java.version | awk -F \" '{print $2}' | awk -F . '{print $1}'
    fi
    rm -rf /tmp/java.version
    #java -XshowSettings:properties -version 2>&1 | perl -e 'while(<>){$rc=$1 if /^\s+java\.version = (\d+)/;}$rc=8 if $rc==1;exit($rc);'
}

die()
{
    if [ -n "$1" ]; then
        echo "$@" 1>&2
    else
        echo "Error occured and quite" 1>&2
    fi
    exit 1
}

logger()
{
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
    eval "$@"
}

prepend()
{
    if  [[ -n "$2" ]] && [[ -d "$2" ]] ; then
        . ${TONE_BM_RUN_DIR}/.shrc
        local fullpath=`realpath $2`
        eval $1=\"$fullpath\$\{$1:+':'\$$1\}\"
        export $1=`eval echo '$'$1`
        echo "export $1=`eval echo '$'$1`" >> ${TONE_BM_RUN_DIR}/.shrc
    else
        echo "\$2=$2 is not a regular directory!"
    fi
}

prependCommon()
{
    if  [[ -n "$2" ]] ; then
        . ${TONE_BM_RUN_DIR}/.shrc
        eval $1=\"$2\$\{$1:+':'\$$1\}\"
        export $1=`eval echo '$'$1`
        echo "export $1=`eval echo '$'$1`" >> ${TONE_BM_RUN_DIR}/.shrc
    else
        echo "\$2=$2 is empty!"
    fi
}

creatSymbollink()
{
    if [[ -z "$2" ]] ; then
        die "please input two args!"
    fi
    local dir=$1
    local target=$2
    if [[ -z "$3" ]] ; then
        if [[ ! -f ${dir}/${target} ]] ; then
            pushd ${dir}
            local source=`find . -maxdepth 1 -mindepth 1 -name "${target}*" ! -type l | head -n 1 | sed "s|./||"`
            if [ -z "${source}" ] ; then
                echo "can't find ${target} symbol-link source file!"
                popd
                return
            fi
            echo "creat symbol-link: ln -s ${source} ${target}"
            sudo ln -s ${source} ${target}
            popd
            return
        fi
    else
        local source=$3
        if [[ ! -f ${dir}/${target} ]] ; then
            pushd ${dir}
            echo "creat symbol-link: ln -s ${source} ${target}"
            sudo ln -s ${source} ${target}
            popd
        fi
        return
    fi
}

get_specific_strings() {
    # keywords, excludes, inputs are splited by ','
    local inputs=$1
    local justOne=${2:-1}
    local keywords=${3:-}
    local excludes=${4:-}
    [ -z "${inputs}" ] && die "inputs shouldn't be null!"
    oldIFS=$IFS
    IFS=","
    keywordsArray=(${keywords})
    excludesArray=(${excludes})
    target=""
    for input in ${inputs}
    do
        if [ -n "${excludes}" ];then
            flag=0
            for exclude in ${excludesArray[@]}
            do
                if [ -n ${exclude} ] && [ -n "$(echo \"${input}\" | grep \"${exclude}\")" ];then
                    flag=1
                    break
                fi
            done
            [ "${flag}" -eq 1 ] && continue
        fi
        if [ -n "${keywords}" ];then
            cnt=0
            for keyword in ${keywordsArray[@]}
            do
                [ -z "${keyword}" ] || [ -z "${input}" ] && break
                [ -z "$(echo ${input} | grep ${keyword})" ] && break
                let cnt++
            done
            if [ "${cnt}" -eq ${#keywordsArray[@]} ];then
                if [ "${justOne}" -eq 1 ];then
                   target=${input} && break
                else
                   if [ -z "${target}" ];then
                       target=${input}
                   else
                       [ -z "$(echo ${target} | grep ${input})" ] && target="${target},${input}"
                   fi
                fi
            fi
        fi
    done
    IFS=${oldIFS}
    echo "${target}"
}

export -f pack_core_dump_file die logger prepend prependCommon wget_wrapper die
